package org.atguigu.config;

import org.atguigu.filter.TokenFilter;
import org.atguigu.handler.MyAccessDeniedHandler;
import org.atguigu.handler.MyAuthenticationFailureHandler;
import org.atguigu.handler.MyAuthenticationSuccessHandler;
import org.atguigu.handler.MyLogoutSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

//开启方法权限检查
@EnableMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfig {
    @Autowired
    MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    @Autowired
    MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    @Autowired
    MyLogoutSuccessHandler myLogoutSuccessHandler;
    @Autowired
    MyAccessDeniedHandler myAccessDeniedHandler;
    @Autowired
    private TokenFilter tokenFilter;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public CorsConfigurationSource configurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedOrigins(Arrays.asList("*")); //允许任何来源 http://localhost:8080
        corsConfiguration.setAllowedMethods(Arrays.asList("*")); //允许任何请求方法 get post put delete
        corsConfiguration.setAllowedHeaders(Arrays.asList("*")); //允许任何请求头 header
        //配置任何接口都允许跨域
        source.registerCorsConfiguration("/**", corsConfiguration);//注册所有接口地址都允许上面的配置
        return source;
    }

    /**
     * 配置安全过滤器链
     *
     * @return
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity, CorsConfigurationSource configurationSource) throws Exception {
        //设置登录页面路径
        DefaultSecurityFilterChain defaultSecurityFilterChain = httpSecurity
                //登录页面
                .formLogin((formLogin) -> {
                    formLogin
                            //url要与页面登录按钮的action地址相同
                            .loginProcessingUrl("/user/login")
                            //登录成功之后执行该handler
                            .successHandler(myAuthenticationSuccessHandler)
                            //登录失败之后执行该handler
                            .failureHandler(myAuthenticationFailureHandler);
                })
                .authorizeHttpRequests((authorizeHttpRequests) -> {
                    //所有请求都需要认证(登录)，仅针对我们自己写的controller接口，spring security所提供的接口不会被拦截
                    //比如这里的登录接口(/user/login)退出登录接口(/user/logout)
                    authorizeHttpRequests.anyRequest().authenticated();
                })
                .csrf((csrf) -> {
                    //禁用csrf验证(跨站伪造网络请求)
                    csrf.disable();
                })
                .cors((cors) -> {
                    //跨域配置
                    cors.configurationSource(configurationSource);
                })
                .sessionManagement((sessionManagementConfigurer) -> {
                    //session创建策略，前后端分离项目通信，使用jwt，不是使用session通信，不需要产生session
                    sessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
                })
                .logout((logoutConfigurer) -> {
                    logoutConfigurer.logoutUrl("/user/logout")//退出请求提交的地址
                            .logoutSuccessHandler(myLogoutSuccessHandler);//退出成功之后走的回调
                    //spring security没有退出失败的handler
                })
                //登录之后的filter加入TokenFilter
                .addFilterBefore(tokenFilter, LogoutFilter.class)
                .exceptionHandling((exceptionHandlingCustomizer) -> {
                    exceptionHandlingCustomizer.accessDeniedHandler(myAccessDeniedHandler);
                })
                .build();

        return defaultSecurityFilterChain;
    }
}
